#include "chat_client.h"
#include <iostream>
namespace  client{

//------------------------客户端初始化-------------------------------------
//主要是初始化socket
int ChatClient::Init(const std::string& server_ip,short port)
{
  //创建udp的socket
  _sock=socket(AF_INET,SOCK_DGRAM,0);
  if(_sock<0)
  {
    perror("socket");
    return -1;
  }
  server_addr.sin_family=AF_INET;
  server_addr.sin_addr.s_addr=inet_addr(server_ip.c_str());
  server_addr.sin_port=htons(port);
  return 0;
}
//-------------------------设置用户信息----------------------------------------
//姓名和学校
//客户端启动时提示输入昵称和学校，从标准输入读取传给该函数
int ChatClient::SetUserInfo(const std::string& name,const std::string& school)
{
  _name=name;
  _school=school;
  return 0;
}
//--------------------------发送消息-------------------------------------------
void ChatClient::SendMsg(const std::string& msg)
{
  //此处若仅仅调用sendto将用户输入的msg发送给服务器是错误的
  //服务器和客户端交互的接口要严格按照服务器提供的api来操作
  //这样的约定就相当于自定制了应用层协议
  //
  //应该自己构造Data结构体中的各个字段进行发送
  //1.数据准备
  server::Data data;
  data.name=_name;
  data.school=_school;
  data.msg=msg;
  //此处对用户下线情况进行处理
  if(msg=="quit"||msg=="exit"||msg=="Q"||msg=="q")
  {
    data.cmd="quit";
  }
  //定义一个字符串保存序列化后的内容
  std::string str;
  data.serialize(&str);
  
  //printf("data:%s\n",str.c_str());

  //2.真正的发送数据
  //printf("serverIP:%s  server_port:%d\n",inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port));
  int ret=sendto(_sock,str.c_str(),str.size(),0,(sockaddr*)&server_addr,sizeof(server_addr));
  if(ret<0)
  {
    printf("client sendmsg failed!\n");
  }
}
//--------------------------接收消息------------------------------------------
//收到的消息是序列化后的数据（Json格式）
void ChatClient::RecvMsg(server::Data* data)
{
  char buf[10*1024]={0};
  //此处的对端IP和端口号就是服务器的IP和端口号，我们在发送消息时就已知，这里不用获取
  ssize_t read_size=recvfrom(_sock,buf,sizeof(buf)-1,0,NULL,NULL);
  if(read_size<0)
  {
    perror("recvfrom");
    return;
  }
  buf[read_size]='\0';
  data->Unserialize(buf);
  return;
}
}



///////////////////////////////////////////////////////
// 先实现一个简易版本的客户端，来测试服务器和客户端代码
///////////////////////////////////////////////////////

//条件编译
#ifdef TEST_CHAT_CLIENT
void* Send(void* arg)
{
  client::ChatClient* client=reinterpret_cast<client::ChatClient*>(arg);
  while(true)
  {
    std::string msg;
    //std::cout<<"Please input your msg:";
    //fflush(stdout);
    std::cin>>msg;
    client->SendMsg(msg);
  }
  return NULL;
}

void* Recv(void* arg)
{
  client::ChatClient* client=reinterpret_cast<client::ChatClient*>(arg);
  //循环接收数据
  while(true)
  {
    server::Data data;
    client->RecvMsg(&data);
    std::cout<<"["<<data.name<<" from "<<data.school<<"]"<<" <--------> "<<data.msg<<std::endl;
  }
  return NULL;
}

int main(int argc,char* argv[])
{
  if(argc!=3)
  {
    printf("Usage: ./chat_client ip port\n");
    return 1;
  }
  client::ChatClient client;
  client.Init(argv[1],atoi(argv[2]));
  std::string name,school;
  std::cout<<"Please input name:";
  std::cin>>name;
  std::cout<<"Please input school:";
  std::cin>>school;
  client.SetUserInfo(name,school);

  //此处不能够直接发送消息然后接收消息，因为只会收发一次
  //应该创建两个线程专门接收和发送消息
  pthread_t send_id,recv_id;
  pthread_create(&send_id,NULL,Send,&client);
  pthread_create(&recv_id,NULL,Recv,&client);
  pthread_join(send_id,NULL);
  pthread_join(recv_id,NULL);
  return 0;
}
#endif 
